#include <iostream>

#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include <assert.h>
#include <sys/time.h>
#include <sys/resource.h>

#include "daemon.hpp"

void Daemon::daemonize()
{
	// clear file creation mask
	umask(0);

	struct rlimit rl;
	// get maximum number of file descriptors
	if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
	{
		std::cout << "can't get file limit" << std::endl;
		return;
	}

	pid_t pid;
	// become a session leader to lose controlling TTY
	if ((pid = fork()) < 0)
	{
		std::cout << "can't fork" << std::endl;
		return;
	}
	else if (0 != pid)
	{
		// parent exit
		exit(0);
	}

	// become a session leader
	setsid();

	struct sigaction sa;
	// ensure future opens won't allocate controlling TTYs
	sa.sa_handler  = SIG_IGN;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags    = 0;
	if (sigaction(SIGHUP, &sa, NULL) < 0)
	{
		std::cout << "can't ignore SIGHUP" << std::endl;
		return;
	}

	if ((pid = fork()) < 0)
	{
		std::cout << "can't fork" << std::endl;
		return;
	}
	else if (0 != pid)
	{
		exit(0);
	}

	// orphaned process group
	
	// close all open file descriptors
	if (RLIM_INFINITY == rl.rlim_max)
	{
		rl.rlim_max  = 1024;
	}

	for (unsigned int i = 0; i < rl.rlim_max; ++ i)
	{
		close(i);
	}

	// attach file descriptors 0, 1 and 2 to /dev/null
	int fd0 = open("/dev/null", O_RDWR);
	int fd1 = dup(0);
	int fd2 = dup(0);

	assert((fd0 == 0) && (fd1 == 1) && (fd2 == 2));
}

